1 Why data exploration and descriptive statistics?

  1. Reporting on results: not useful to only report a table with the results for each subject
  2. Let the data speak by summarizing and visualizing it
  3. Get insight in the data
  4. Discover errors, anomalies or even fraud
  5. Check assumptions that are required for the downstream statistical inference, e.g. are the data normally distributed

2 Univariate exploration of quantitative variables

2.1 Histogram

NHANES %>% filter(Gender=="female") %>% 
ggplot(aes(x=DirectChol)) + 
geom_histogram(aes(y=..density.., fill=..count..),bins=30) +
geom_density(aes(y=..density..))

  1. Select females and pipe results to ggplot

    NHANES %>% filter(Gender=="female")
  2. Select data to plot

ggplot(aes(x=DirectChol)) +
  1. Equal bins for interpretation, number of bins can be selected with the bins argument to the geom_hist

  2. Relative frequenties to enable visual comparison between histograms

geom_histogram(aes(y=..density.., fill=..count..)) +
  1. If we have enough observations we can use a kernel density estimator of f(x)
geom_density(aes(y=..density..))

2.2 Boxplot

With ggplot we always have to define an x variable if we make a boxplot. If we use a string then all data is put in one category. And one boxplot is constructed.

NHANES %>% filter(Gender=="female") %>%
  ggplot(aes(x="",y=DirectChol)) +
  geom_boxplot() 

So we can add a boxplot to a ggplot figure by using the geom_boxplot function.

If the dataset is small to moderate in size we can also add the raw data to the plot with the geom_point() function and the position="jitter" argument. Note, that we then also set the outlier.shape argument in the geom_boxplot function on NA so that the outliers are not plotted twice.

Here, we will plot again the relative abundances of Staphylococcus from the armpit transplant experiment

ap<-read_csv("https://raw.githubusercontent.com/GTPB/PSLS20/master/data/armpit.csv")
ap
# A tibble: 20 x 2
   trt          rel
   <chr>      <dbl>
 1 placebo     55.0
 2 placebo     31.8
 3 placebo     41.1
 4 placebo     59.5
 5 placebo     63.6
 6 placebo     41.5
 7 placebo     30.4
 8 placebo     43.0
 9 placebo     41.7
10 placebo     33.9
11 transplant  57.2
12 transplant  72.5
13 transplant  61.9
14 transplant  56.7
15 transplant  76  
16 transplant  71.7
17 transplant  57.8
18 transplant  65.1
19 transplant  67.5
20 transplant  77.6
ap %>%  ggplot(aes(x=trt,y=rel)) + geom_boxplot(outlier.shape=NA) + geom_point(position="jitter")

When we specify a factor variable for x, we get a boxplot for each treatment group.

2.3 Descriptive statistics

2.3.1 Central location: Mean or Median?

2.3.1.1 Mean

  • In a period of 30 years males hope to have on average 64.3 partners and females 2.8

2.3.1.2 Median

  • The median of the number of partners males and females want to have is both 1

2.3.1.3 What happens?

desired number of partners

desired number of partners

  • Mean is very sensitive towards outliers!

2.3.2 Geometric mean

\[\sqrt[n]{\prod\limits_{i=1}^n x_i} = \exp\left\{\frac{1}{n} \sum_{i=1}^n \log(x_i)\right\}\]

  • Geometric mean is closer to the mediaan then the mean

  • log-transformation removes skewness

  • Often a more useful measure for the central location than median:

  1. Uses all observations: is more precise
  2. It is the ordinary mean on log-transformed data \(\rightarrow\) classical statistical methods can be directly applied, e.g. hypothesis tests and confidence intervals (see chapter 5)
  3. Useful for many biological characteristics e.g. concentrations that cannot be negative.
  4. Differences on a log scale have the interpretation of a log fold change:

\[\log (B) - \log(A)= \log(\frac{B}{A})=\log(FC_\text{B vs A})\]

logSummary <- 
NHANES %>% filter(Gender=="female") %>% summarize(logMean=mean(DirectChol %>% log,na.rm=TRUE),sd=sd(DirectChol %>% log,na.rm=TRUE),mean=mean(DirectChol,na.rm=TRUE),median=median(DirectChol,na.rm=TRUE)) %>% mutate(geoMean=exp(logMean))

NHANES %>% filter(Gender=="female") %>%
ggplot(aes(x=DirectChol %>% log)) + 
geom_histogram(aes(y=..density.., fill=..count..),bins=30) +
geom_density(aes(y=..density..)) +
  stat_function(fun=dnorm,color="red",args=list(mean=logSummary$mean, sd=logSummary$sd))

logSummary
    logMean        sd     mean median  geoMean
1 0.3564553 0.2731811 1.482467   1.42 1.428258
  • Indeed the mean is pulled to larger values by the skewed data
  • The geometric mean is closer to the median
  • The cholestorol data are much more symmetric upon log transformation and the approximation by a normal distribution is good.

2.4 Descriptives for the variability

The variability around the central value is crucial:

  1. Biologists are often interested in how animals or plants are spread in the study region.
  2. Compare groups: the group effect is more clear when the response has less variability. Quantifying variability is crucial to distinguish between systematic and random patterns.
  • The response varies between and within individuals and is the reason why we need statistics.

  • Crucial to describe both the central location and the variability.
  • Which part of the variability can we explain (e.g. with characteristics treatment, age, etc,) and which part is unexplained? ### Sample variance and sample standard deviation

  • Sample variance: \[ s_X^2= \sum\limits_{i=1}^n \frac{(X-\bar X)^2}{n-1} \]
  • Interpretation is often difficult because it is in another unit than the measurements

  • Standard deviation: \[ s_X= \sqrt{s_x^2} \]

  • Very useful for Normal distributed observations:

    • 68% of the observations falls in the interval \(\bar{x} - s_x\) en \(\bar{x} + s_x\)
    • 95% of the observations falls in the interval \(\bar{x} - 2 s_x\) en \(\bar{x} + 2 s_x\).
  • These intervals are referred to as 68% en 95% reference-intervals.

  • If the data are not normally distributed reference intervals are not valid

2.4.1 Interquartile range

For skewed data the standard deviation is not useful - It is very sensitive to outliers - Inter Quartile Range: Distance between first and third quartile - Width of the boxplot!

NHANES %>% filter(Gender=="female") %>% summarize(IQR=IQR(DirectChol,na.rm=TRUE))
   IQR
1 0.52
NHANES %>% filter(Gender=="female") %>%
  ggplot(aes(x="",y=DirectChol)) +
  geom_boxplot() 

3 Normale approximation

  • Biological and chemical data are often normally distributed upon transformation.

  • If this is the case we can get a lot of insight in the data using just to descriptive statistics: gemiddelde \(\mu\) en standaard deviatie \(\sigma\).

3.1 Evaluation with QQ-plots

If your analysis build upon the assumption that the data are Normally distributed it has to be verified.

We use QQ-plots or quantile-quantile plots).

  • Observed quantiles from the observations in the sample are plotted against quantiles from the Normale distribution.

  • If the data are normally distributed both quantiles have to be in line.

  • Dots in the plot are expected on a straight line

  • Systematic deviations of the straight line indicate that the data are not normally distributed.

  • Note, that we will always observe some random deviations from the straight line in the plot because of random biological variability, which is not indicative for deviations from Normality.

  • So it is important to train yourself to learn to distinguish systematic from random deviations.

3.1.1 Normal data

  • We will first simulate data from the normal distribution to show how the plots look like for data that is meeting the assumptions.

  • We will simulate data from 9 samples with a mean of 18 and standard deviation of 9

n <- 20
mu <- 18
sigma <- 9
nSamp <-9

normSim <- matrix(rnorm(n*nSamp,mean=mu,sd=sigma),nrow=n) %>% as.data.frame

normSim %>% gather(samp,data) %>% 
ggplot(aes(x=data)) +
geom_histogram(aes(y=..density.., fill=..count..),bins=30) +
geom_density(aes(y=..density..)) +
  facet_wrap(~samp)

normSim %>% gather(samp,data) %>% 
  ggplot(aes(sample=data)) +
  geom_qq() +
  geom_qq_line() +
facet_wrap(~samp)

So even for normal data we observe some deviations!

3.1.2 Real data

NHANES %>% filter(Gender=="female"&!is.na(BMI)) %>%
  ggplot(aes(x=BMI))+
   geom_histogram(aes(y=..density.., fill=..count..)) +
   xlab("BMI") +
   ggtitle("All females in study") +
  geom_density(aes(y=..density..))

NHANES %>% filter(Gender=="female"&!is.na(BMI)) %>%
  ggplot(aes(sample=BMI)) +
  geom_qq() +
  geom_qq_line()

The QQ-plot shows that the quantiles of the data - are larger (above the line) than these from the Normal in the left tail: compression of the lower tail - are larger (above the line) than these from the Normal in the right tail: long tail to the right - We can clearly see that the data are skewed

LS0tCnRpdGxlOiAiNC4gRGF0YSBFeHBsb3JhdGlvbiIKb3V0cHV0OgogICAgaHRtbF9kb2N1bWVudDoKICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgICB0aGVtZTogY29zbW8KICAgICAgdG9jOiB0cnVlCiAgICAgIHRvY19mbG9hdDogdHJ1ZQogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQotLS0KCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGluY2x1ZGUgPSBUUlVFLCBjb21tZW50ID0gTkEsIGVjaG8gPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFJtaXNjKQpsaWJyYXJ5KE5IQU5FUykKYGBgCgpgYGB7ciBwb3AyU2FtcDJQb3AsIG91dC53aWR0aD0nODAlJyxmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KaWYgKCJwaSIlaW4lbHMoKSkgcm0oInBpIikKa29wdm9ldGVyPC1mdW5jdGlvbih4LHksYW5nbGU9MCxsPS4yLGNleC5kb3Q9LjUscGNoPTE5LGNvbD0iYmxhY2siKQp7CmFuZ2xlPWFuZ2xlLzE4MCpwaQpwb2ludHMoeCx5LGNleD1jZXguZG90LHBjaD1wY2gsY29sPWNvbCkKbGluZXMoYyh4LHgrbCpjb3MoLXBpLzIrYW5nbGUpKSxjKHkseStsKnNpbigtcGkvMithbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsLzIqY29zKC1waS8yK2FuZ2xlKSx4K2wvMipjb3MoLXBpLzIrYW5nbGUpK2wvNCpjb3MoYW5nbGUpKSxjKHkrbC8yKnNpbigtcGkvMithbmdsZSkseStsLzIqc2luKC1waS8yK2FuZ2xlKStsLzQqc2luKGFuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wvMipjb3MoLXBpLzIrYW5nbGUpLHgrbC8yKmNvcygtcGkvMithbmdsZSkrbC80KmNvcyhwaSthbmdsZSkpLGMoeStsLzIqc2luKC1waS8yK2FuZ2xlKSx5K2wvMipzaW4oLXBpLzIrYW5nbGUpK2wvNCpzaW4ocGkrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbCpjb3MoLXBpLzIrYW5nbGUpLHgrbCpjb3MoLXBpLzIrYW5nbGUpK2wvMipjb3MoLXBpLzIrcGkvNCthbmdsZSkpLGMoeStsKnNpbigtcGkvMithbmdsZSkseStsKnNpbigtcGkvMithbmdsZSkrbC8yKnNpbigtcGkvMitwaS80K2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wqY29zKC1waS8yK2FuZ2xlKSx4K2wqY29zKC1waS8yK2FuZ2xlKStsLzIqY29zKC1waS8yLXBpLzQrYW5nbGUpKSxjKHkrbCpzaW4oLXBpLzIrYW5nbGUpLHkrbCpzaW4oLXBpLzIrYW5nbGUpK2wvMipzaW4oLXBpLzItcGkvNCthbmdsZSkpLGNvbD1jb2wpCn0KCnBhcihtYXI9YygwLDAsMCwwKSxtYWk9YygwLDAsMCwwKSkKcGxvdCgwLDAseGxhYj0iIix5bGFiPSIiLHhsaW09YygwLDEwKSx5bGltPWMoMCwxMCksY29sPTAseGF4dD0ibm9uZSIseWF4dD0ibm9uZSIsYXhlcz1GQUxTRSkKcmVjdCgwLDYsMTAsMTAsYm9yZGVyPSJyZWQiLGx3ZD0yKQp0ZXh0KC41LDgsInBvcHVsYXRpb24iLHNydD05MCxjb2w9InJlZCIsY2V4PTIpCnN5bWJvbHMgKDMsIDgsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9InJlZCIsaW5jaGVzPUZBTFNFLGx3ZD0yKQpzZXQuc2VlZCgzMzApCmdyaWQ9c2VxKDAsMS4zLC4wMSkKCmZvciAoaSBpbiAxOjUwKQp7CglhbmdsZTE9cnVuaWYobj0xLG1pbj0wLG1heD0zNjApCglhbmdsZTI9cnVuaWYobj0xLG1pbj0wLG1heD0zNjApCglyYWRpdXM9c2FtcGxlKGdyaWQscHJvYj1ncmlkXjIqcGkvc3VtKGdyaWReMipwaSksc2l6ZT0xKQoJa29wdm9ldGVyKDMrcmFkaXVzKmNvcyhhbmdsZTEvMTgwKnBpKSw4K3JhZGl1cypzaW4oYW5nbGUxLzE4MCpwaSksYW5nbGU9YW5nbGUyKQp9CnRleHQoNy41LDgsIkNob2xlc3Rvcm9sIGluIHBvcHVsYXRpb24iLGNvbD0icmVkIixjZXg9MS4yKQoKcmVjdCgwLDAsMTAsNCxib3JkZXI9ImJsdWUiLGx3ZD0yKQp0ZXh0KC41LDIsInNhbXBsZSIsc3J0PTkwLGNvbD0iYmx1ZSIsY2V4PTIpCnN5bWJvbHMgKDMsIDIsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9ImJsdWUiLGluY2hlcz1GQUxTRSxsd2Q9MikKZm9yIChpIGluIDA6MikKCWZvciAoaiBpbiAwOjQpCnsKCglrb3B2b2V0ZXIoMi4xK2oqKDMuOS0yLjEpLzQsMS4xK2kpCn0KdGV4dCg3LjUsMiwiQ2hvbGVzdG9yb2wgaW4gc2FtcGxlIixjb2w9ImJsdWUiLGNleD0xLjIpCgphcnJvd3MoMyw1LjksMyw0LjEsY29sPSJibGFjayIsbHdkPTMpCmFycm93cyg3LDQuMSw3LDUuOSxjb2w9ImJsYWNrIixsd2Q9MykKdGV4dCgxLjUsNSwiRVhQLiBERVNJR04gKDEpIixjb2w9ImJsYWNrIixjZXg9MS4yKQp0ZXh0KDguNSw1LCJFU1RJTUFUSU9OICZcbklORkVSRU5DRSAoMykiLGNvbD0iYmxhY2siLGNleD0xLjIpCnRleHQoNy41LC41LCJEQVRBIEVYUExPUkFUSU9OICZcbkRFU0NSSVBUSVZFIFNUQVRJU1RJQ1MgKDIpIixjb2w9ImJsYWNrIixjZXg9MS4yKQpgYGAKCiMgV2h5IGRhdGEgZXhwbG9yYXRpb24gYW5kIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3M/CgoxLiBSZXBvcnRpbmcgb24gcmVzdWx0czogbm90IHVzZWZ1bCB0byBvbmx5IHJlcG9ydCBhIHRhYmxlIHdpdGggdGhlIHJlc3VsdHMgZm9yIGVhY2ggc3ViamVjdAoyLiBMZXQgdGhlIGRhdGEgc3BlYWsgYnkgc3VtbWFyaXppbmcgYW5kIHZpc3VhbGl6aW5nIGl0CjMuIEdldCBpbnNpZ2h0IGluIHRoZSBkYXRhCjQuIERpc2NvdmVyIGVycm9ycywgYW5vbWFsaWVzIG9yIGV2ZW4gZnJhdWQKNS4gQ2hlY2sgYXNzdW1wdGlvbnMgdGhhdCBhcmUgcmVxdWlyZWQgZm9yIHRoZSBkb3duc3RyZWFtIHN0YXRpc3RpY2FsIGluZmVyZW5jZSwgZS5nLiBhcmUgdGhlIGRhdGEgbm9ybWFsbHkgZGlzdHJpYnV0ZWQKCgojIFVuaXZhcmlhdGUgZXhwbG9yYXRpb24gb2YgcXVhbnRpdGF0aXZlIHZhcmlhYmxlcwoKCiMjIEhpc3RvZ3JhbQoKYGBge3IsZWNobz1GQUxTRX0KbGlicmFyeShOSEFORVMpCmBgYAoKYGBge3J9Ck5IQU5FUyAlPiUgZmlsdGVyKEdlbmRlcj09ImZlbWFsZSIpICU+JSAKZ2dwbG90KGFlcyh4PURpcmVjdENob2wpKSArIApnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiwgZmlsbD0uLmNvdW50Li4pLGJpbnM9MzApICsKZ2VvbV9kZW5zaXR5KGFlcyh5PS4uZGVuc2l0eS4uKSkKYGBgCgoKMS4gU2VsZWN0IGZlbWFsZXMgYW5kIHBpcGUgcmVzdWx0cyB0byBnZ3Bsb3QKYGBgCk5IQU5FUyAlPiUgZmlsdGVyKEdlbmRlcj09ImZlbWFsZSIpCmBgYAoKMi4gU2VsZWN0IGRhdGEgdG8gcGxvdAoKYGBgCmdncGxvdChhZXMoeD1EaXJlY3RDaG9sKSkgKwpgYGAKCjMuIEVxdWFsIGJpbnMgZm9yIGludGVycHJldGF0aW9uLCBudW1iZXIgb2YgYmlucyBjYW4gYmUgc2VsZWN0ZWQgd2l0aCB0aGUgYmlucyBhcmd1bWVudCB0byB0aGUgZ2VvbV9oaXN0Cgo0LiAqUmVsYXRpdmUqIGZyZXF1ZW50aWVzIHRvIGVuYWJsZSB2aXN1YWwgY29tcGFyaXNvbiBiZXR3ZWVuIGhpc3RvZ3JhbXMKCmBgYApnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiwgZmlsbD0uLmNvdW50Li4pKSArCmBgYAoKNS4gSWYgd2UgaGF2ZSBlbm91Z2ggb2JzZXJ2YXRpb25zIHdlIGNhbiB1c2UgYSBrZXJuZWwgZGVuc2l0eSBlc3RpbWF0b3Igb2YgZih4KQoKYGBgCmdlb21fZGVuc2l0eShhZXMoeT0uLmRlbnNpdHkuLikpCmBgYAoKIyMgQm94cGxvdAoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmZlbSA8LSBOSEFORVMgJT4lIGZpbHRlcihHZW5kZXI9PSJmZW1hbGUiICYgIWlzLm5hKERpcmVjdENob2wpKSAlPiUgc2VsZWN0KERpcmVjdENob2wpCmJveHBsb3QoZmVtJERpcmVjdENob2wsIHlsYWI9IkRpcmVjdCBDaG9sZXN0b3JvbCIsY2V4LmxhYj0xLjUsY2V4LmF4aXM9MS41LGNleC5tYWluPTEuNSkKcmFuZ2VDbDwtcXVhbnRpbGUoZmVtJERpcmVjdENob2wsYyguMjUsLjc1KSkrYygtMSwxKSpkaWZmKHF1YW50aWxlKGZlbSREaXJlY3RDaG9sLGMoLjI1LC43NSkpKSoxLjUKYm94WXM8LWMocmFuZ2UoZmVtJERpcmVjdENob2xbZmVtJERpcmVjdENob2w8PXJhbmdlQ2xbMl0mZmVtJERpcmVjdENob2w+PXJhbmdlQ2xbMV1dKSxxdWFudGlsZShmZW0kRGlyZWN0Q2hvbCxjKC4yNSwuNSwuNzUpKSxyYW5nZUNsWzJdKyhtYXgoZmVtJERpcmVjdENob2wpLXJhbmdlQ2xbMl0pLzIpCnRleHQoMS4zLGJveFlzLGxhYmVscz1jKCJ3aXNrZXIiLCJ3aXNrZXIiLCJ4MjUiLCJtZWRpYWFuIiwieDc1Iiwib3V0bGllcnMiKSxwb3M9NCxjZXg9MS4zKQpsaW5lcyhjKDEuMSwxLjMsMS4zLDEuMSksYyhyYW5nZUNsWzJdLHJhbmdlQ2xbMl0rKG1heChmZW0kRGlyZWN0Q2hvbCktcmFuZ2VDbFsyXSkvMixyYW5nZUNsWzJdKyhtYXgoZmVtJERpcmVjdENob2wpLXJhbmdlQ2xbMl0pLzIsbWF4KGZlbSREaXJlY3RDaG9sKSksbHR5PTIpCmBgYAoKV2l0aCBnZ3Bsb3Qgd2UgYWx3YXlzIGhhdmUgdG8gZGVmaW5lIGFuIHggdmFyaWFibGUgaWYgd2UgbWFrZSBhIGJveHBsb3QuIElmIHdlIHVzZSBhIHN0cmluZyB0aGVuIGFsbCBkYXRhIGlzIHB1dCBpbiBvbmUgY2F0ZWdvcnkuIApBbmQgb25lIGJveHBsb3QgaXMgY29uc3RydWN0ZWQuCgpgYGB7cn0KTkhBTkVTICU+JSBmaWx0ZXIoR2VuZGVyPT0iZmVtYWxlIikgJT4lCiAgZ2dwbG90KGFlcyh4PSIiLHk9RGlyZWN0Q2hvbCkpICsKICBnZW9tX2JveHBsb3QoKSAKYGBgCgpTbyB3ZSBjYW4gYWRkIGEgYm94cGxvdCB0byBhIGdncGxvdCBmaWd1cmUgYnkgdXNpbmcgdGhlIGdlb21fYm94cGxvdCBmdW5jdGlvbi4gCgpJZiB0aGUgZGF0YXNldCBpcyBzbWFsbCB0byBtb2RlcmF0ZSBpbiBzaXplIHdlIGNhbiBhbHNvIGFkZCB0aGUgcmF3IGRhdGEgdG8gdGhlIHBsb3Qgd2l0aCB0aGUgYGdlb21fcG9pbnQoKWAgZnVuY3Rpb24gYW5kIHRoZSBgcG9zaXRpb249ImppdHRlciJgIGFyZ3VtZW50LiBOb3RlLCB0aGF0IHdlIHRoZW4gYWxzbyBzZXQgdGhlIGBvdXRsaWVyLnNoYXBlYCBhcmd1bWVudCBpbiB0aGUgYGdlb21fYm94cGxvdGAgZnVuY3Rpb24gb24gTkEgc28gdGhhdCB0aGUgb3V0bGllcnMgYXJlIG5vdCBwbG90dGVkIHR3aWNlLiAKCkhlcmUsIHdlIHdpbGwgcGxvdCBhZ2FpbiB0aGUgcmVsYXRpdmUgYWJ1bmRhbmNlcyBvZiAqKlN0YXBoeWxvY29jY3VzKiogZnJvbSB0aGUgYXJtcGl0IHRyYW5zcGxhbnQgZXhwZXJpbWVudAoKYGBge3J9CmFwPC1yZWFkX2NzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0dUUEIvUFNMUzIwL21hc3Rlci9kYXRhL2FybXBpdC5jc3YiKQphcAoKYXAgJT4lICBnZ3Bsb3QoYWVzKHg9dHJ0LHk9cmVsKSkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKyBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKQpgYGAKCldoZW4gd2Ugc3BlY2lmeSBhIGZhY3RvciB2YXJpYWJsZSBmb3IgeCwgd2UgZ2V0IGEgYm94cGxvdCBmb3IgZWFjaCB0cmVhdG1lbnQgZ3JvdXAuCgoKIyMgRGVzY3JpcHRpdmUgc3RhdGlzdGljcyAKCiMjIyBDZW50cmFsIGxvY2F0aW9uOiBNZWFuIG9yIE1lZGlhbj8KCiMjIyMgTWVhbgotIEluIGEgcGVyaW9kIG9mIDMwIHllYXJzIG1hbGVzIGhvcGUgdG8gaGF2ZSBvbiBhdmVyYWdlIDY0LjMgcGFydG5lcnMgYW5kIGZlbWFsZXMgMi44ICBcdGlueXsoTWlsbGVyIGFuZCBGaXNoa2luLCAxOTk3KX1cbm9ybWFsc2l6ZQoKIyMjIyBNZWRpYW4KCi0gVGhlIG1lZGlhbiBvZiB0aGUgbnVtYmVyIG9mIHBhcnRuZXJzIG1hbGVzIGFuZCBmZW1hbGVzIHdhbnQgdG8gaGF2ZSBpcyBib3RoIDEgXHRpbnl7KE1pbGxlciBhbmQgRmlzaGtpbiwgMTk5Nyl9XG5vcm1hbHNpemUKCiMjIyMgV2hhdCBoYXBwZW5zPyAKCiFbZGVzaXJlZCBudW1iZXIgb2YgcGFydG5lcnNdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9HVFBCL1BTTFMyMC9naC1wYWdlcy9hc3NldHMvZmlncy9wYXJ0bmVycy5wbmcpe3dpZHRoPTc1JX0KCi0gTWVhbiBpcyB2ZXJ5IHNlbnNpdGl2ZSB0b3dhcmRzIG91dGxpZXJzIQoKCiMjIyBHZW9tZXRyaWMgbWVhbgoKJCRcc3FydFtuXXtccHJvZFxsaW1pdHNfe2k9MX1ebiB4X2l9ID0gXGV4cFxsZWZ0XHtcZnJhY3sxfXtufSBcc3VtX3tpPTF9Xm4gXGxvZyh4X2kpXHJpZ2h0XH0kJAoKLSBHZW9tZXRyaWMgbWVhbiBpcyBjbG9zZXIgdG8gdGhlIG1lZGlhYW4gdGhlbiB0aGUgbWVhbgoKLSBsb2ctdHJhbnNmb3JtYXRpb24gcmVtb3ZlcyBza2V3bmVzcyAKCi0gT2Z0ZW4gYSBtb3JlIHVzZWZ1bCBtZWFzdXJlIGZvciB0aGUgY2VudHJhbCBsb2NhdGlvbiB0aGFuIG1lZGlhbjoKCjEuIFVzZXMgYWxsIG9ic2VydmF0aW9uczogaXMgbW9yZSBwcmVjaXNlIAoyLiBJdCBpcyB0aGUgb3JkaW5hcnkgbWVhbiBvbiBsb2ctdHJhbnNmb3JtZWQgZGF0YSAkXHJpZ2h0YXJyb3ckIGNsYXNzaWNhbCBzdGF0aXN0aWNhbCBtZXRob2RzIGNhbiBiZSBkaXJlY3RseSBhcHBsaWVkLCBlLmcuIGh5cG90aGVzaXMgdGVzdHMgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIChzZWUgY2hhcHRlciA1KQozLiBVc2VmdWwgZm9yIG1hbnkgYmlvbG9naWNhbCBjaGFyYWN0ZXJpc3RpY3MgZS5nLiBjb25jZW50cmF0aW9ucyB0aGF0IGNhbm5vdCBiZSBuZWdhdGl2ZS4KNC4gRGlmZmVyZW5jZXMgb24gYSBsb2cgc2NhbGUgaGF2ZSB0aGUgaW50ZXJwcmV0YXRpb24gb2YgYSBsb2cgZm9sZCBjaGFuZ2U6IAoKJCRcbG9nIChCKSAtIFxsb2coQSk9IFxsb2coXGZyYWN7Qn17QX0pPVxsb2coRkNfXHRleHR7QiB2cyBBfSkkJAoKCmBgYHtyfQpsb2dTdW1tYXJ5IDwtIApOSEFORVMgJT4lIGZpbHRlcihHZW5kZXI9PSJmZW1hbGUiKSAlPiUgc3VtbWFyaXplKGxvZ01lYW49bWVhbihEaXJlY3RDaG9sICU+JSBsb2csbmEucm09VFJVRSksc2Q9c2QoRGlyZWN0Q2hvbCAlPiUgbG9nLG5hLnJtPVRSVUUpLG1lYW49bWVhbihEaXJlY3RDaG9sLG5hLnJtPVRSVUUpLG1lZGlhbj1tZWRpYW4oRGlyZWN0Q2hvbCxuYS5ybT1UUlVFKSkgJT4lIG11dGF0ZShnZW9NZWFuPWV4cChsb2dNZWFuKSkKCk5IQU5FUyAlPiUgZmlsdGVyKEdlbmRlcj09ImZlbWFsZSIpICU+JQpnZ3Bsb3QoYWVzKHg9RGlyZWN0Q2hvbCAlPiUgbG9nKSkgKyAKZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4sIGZpbGw9Li5jb3VudC4uKSxiaW5zPTMwKSArCmdlb21fZGVuc2l0eShhZXMoeT0uLmRlbnNpdHkuLikpICsKICBzdGF0X2Z1bmN0aW9uKGZ1bj1kbm9ybSxjb2xvcj0icmVkIixhcmdzPWxpc3QobWVhbj1sb2dTdW1tYXJ5JG1lYW4sIHNkPWxvZ1N1bW1hcnkkc2QpKQoKbG9nU3VtbWFyeQpgYGAKCi0gSW5kZWVkIHRoZSBtZWFuIGlzIHB1bGxlZCB0byBsYXJnZXIgdmFsdWVzIGJ5IHRoZSBza2V3ZWQgZGF0YQotIFRoZSBnZW9tZXRyaWMgbWVhbiBpcyBjbG9zZXIgdG8gdGhlIG1lZGlhbgotIFRoZSBjaG9sZXN0b3JvbCBkYXRhIGFyZSBtdWNoIG1vcmUgc3ltbWV0cmljIHVwb24gbG9nIHRyYW5zZm9ybWF0aW9uIGFuZCB0aGUgYXBwcm94aW1hdGlvbiBieSBhIG5vcm1hbCBkaXN0cmlidXRpb24gaXMgZ29vZC4gCgoKCiMjIERlc2NyaXB0aXZlcyBmb3IgdGhlIHZhcmlhYmlsaXR5IAoKVGhlIHZhcmlhYmlsaXR5IGFyb3VuZCB0aGUgY2VudHJhbCB2YWx1ZSBpcyBjcnVjaWFsOgoKMS4gQmlvbG9naXN0cyBhcmUgb2Z0ZW4gaW50ZXJlc3RlZCBpbiBob3cgYW5pbWFscyBvciBwbGFudHMgYXJlIHNwcmVhZCBpbiB0aGUgc3R1ZHkgcmVnaW9uLiAKMi4gQ29tcGFyZSBncm91cHM6IHRoZSBncm91cCBlZmZlY3QgaXMgbW9yZSBjbGVhciB3aGVuIHRoZSByZXNwb25zZSBoYXMgbGVzcyB2YXJpYWJpbGl0eS4gUXVhbnRpZnlpbmcgdmFyaWFiaWxpdHkgaXMgY3J1Y2lhbCB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIHN5c3RlbWF0aWMgYW5kIHJhbmRvbSBwYXR0ZXJucy4KCi0gVGhlIHJlc3BvbnNlIHZhcmllcyBiZXR3ZWVuIGFuZCB3aXRoaW4gaW5kaXZpZHVhbHMgYW5kIGlzIHRoZSByZWFzb24gd2h5IHdlIG5lZWQgc3RhdGlzdGljcy4KCi0gQ3J1Y2lhbCB0byBkZXNjcmliZSBib3RoIHRoZSBjZW50cmFsIGxvY2F0aW9uIGFuZCB0aGUgdmFyaWFiaWxpdHkuCi0gV2hpY2ggcGFydCBvZiB0aGUgdmFyaWFiaWxpdHkgY2FuIHdlIGV4cGxhaW4gKGUuZy4gd2l0aCBjaGFyYWN0ZXJpc3RpY3MgdHJlYXRtZW50LCBhZ2UsIGV0YywpIGFuZCB3aGljaCBwYXJ0IGlzIHVuZXhwbGFpbmVkPyAKIyMjIFNhbXBsZSB2YXJpYW5jZSBhbmQgc2FtcGxlIHN0YW5kYXJkIGRldmlhdGlvbgoKLSBTYW1wbGUgdmFyaWFuY2U6ICQkCnNfWF4yPSBcc3VtXGxpbWl0c197aT0xfV5uIFxmcmFjeyhYLVxiYXIgWCleMn17bi0xfQokJAotIEludGVycHJldGF0aW9uIGlzIG9mdGVuIGRpZmZpY3VsdCBiZWNhdXNlIGl0IGlzIGluIGFub3RoZXIgdW5pdCB0aGFuIHRoZSBtZWFzdXJlbWVudHMKCi0gKlN0YW5kYXJkIGRldmlhdGlvbio6ICQkCnNfWD0gXHNxcnR7c194XjJ9CiQkCgotIFZlcnkgdXNlZnVsIGZvciBOb3JtYWwgZGlzdHJpYnV0ZWQgb2JzZXJ2YXRpb25zOgoKICAgIC0gNjglIG9mIHRoZSBvYnNlcnZhdGlvbnMgZmFsbHMgaW4gdGhlIGludGVydmFsICAkXGJhcnt4fSAtIHNfeCQgZW4gJFxiYXJ7eH0gKyBzX3gkCiAgICAtIDk1JSBvZiB0aGUgb2JzZXJ2YXRpb25zIGZhbGxzIGluIHRoZSBpbnRlcnZhbCAkXGJhcnt4fSAtIDIgc194JCBlbiAkXGJhcnt4fSArIDIgc194JC4KCi0gVGhlc2UgaW50ZXJ2YWxzIGFyZSByZWZlcnJlZCB0byBhcyA2OCUgZW4gOTUlICpyZWZlcmVuY2UtaW50ZXJ2YWxzKi4KCi0gSWYgdGhlIGRhdGEgYXJlIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZCByZWZlcmVuY2UgaW50ZXJ2YWxzIGFyZSBub3QgdmFsaWQgCgojIyMgSW50ZXJxdWFydGlsZSByYW5nZQoKRm9yIHNrZXdlZCBkYXRhIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gaXMgbm90IHVzZWZ1bAotIEl0IGlzIHZlcnkgc2Vuc2l0aXZlIHRvIG91dGxpZXJzCi0gKkludGVyIFF1YXJ0aWxlIFJhbmdlKjogRGlzdGFuY2UgYmV0d2VlbiBmaXJzdCBhbmQgdGhpcmQgcXVhcnRpbGUgCi0gV2lkdGggb2YgdGhlIGJveHBsb3QhCgpgYGB7cn0KTkhBTkVTICU+JSBmaWx0ZXIoR2VuZGVyPT0iZmVtYWxlIikgJT4lIHN1bW1hcml6ZShJUVI9SVFSKERpcmVjdENob2wsbmEucm09VFJVRSkpCmBgYAoKCmBgYHtyfQpOSEFORVMgJT4lIGZpbHRlcihHZW5kZXI9PSJmZW1hbGUiKSAlPiUKICBnZ3Bsb3QoYWVzKHg9IiIseT1EaXJlY3RDaG9sKSkgKwogIGdlb21fYm94cGxvdCgpIApgYGAKCgojIE5vcm1hbGUgYXBwcm94aW1hdGlvbgoKCi0gQmlvbG9naWNhbCBhbmQgY2hlbWljYWwgZGF0YSBhcmUgb2Z0ZW4gbm9ybWFsbHkgZGlzdHJpYnV0ZWQgdXBvbiB0cmFuc2Zvcm1hdGlvbi4gCgotIElmIHRoaXMgaXMgdGhlIGNhc2Ugd2UgY2FuIGdldCBhIGxvdCBvZiBpbnNpZ2h0IGluIHRoZSBkYXRhIHVzaW5nIGp1c3QgdG8gZGVzY3JpcHRpdmUgc3RhdGlzdGljczogZ2VtaWRkZWxkZSAkXG11JCBlbiBzdGFuZGFhcmQgZGV2aWF0aWUgJFxzaWdtYSQuCgoKIyMgRXZhbHVhdGlvbiB3aXRoIFFRLXBsb3RzCgpJZiB5b3VyIGFuYWx5c2lzIGJ1aWxkIHVwb24gdGhlIGFzc3VtcHRpb24gdGhhdCB0aGUgZGF0YSBhcmUgTm9ybWFsbHkgZGlzdHJpYnV0ZWQgaXQgaGFzIHRvIGJlIHZlcmlmaWVkLgoKV2UgdXNlICpRUS1wbG90cyogb3IgKnF1YW50aWxlLXF1YW50aWxlIHBsb3RzKikuCgotIE9ic2VydmVkIHF1YW50aWxlcyBmcm9tIHRoZSBvYnNlcnZhdGlvbnMgaW4gdGhlIHNhbXBsZSBhcmUgcGxvdHRlZCBhZ2FpbnN0IHF1YW50aWxlcyBmcm9tIHRoZSBOb3JtYWxlIGRpc3RyaWJ1dGlvbi4KCi0gSWYgdGhlIGRhdGEgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGJvdGggcXVhbnRpbGVzIGhhdmUgdG8gYmUgaW4gbGluZS4gCgotIERvdHMgaW4gdGhlIHBsb3QgYXJlIGV4cGVjdGVkIG9uIGEgc3RyYWlnaHQgbGluZQoKLSBTeXN0ZW1hdGljIGRldmlhdGlvbnMgb2YgdGhlIHN0cmFpZ2h0IGxpbmUgaW5kaWNhdGUgdGhhdCB0aGUgZGF0YSBhcmUgbm90IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiAKCi0gTm90ZSwgdGhhdCB3ZSB3aWxsIGFsd2F5cyBvYnNlcnZlIHNvbWUgcmFuZG9tIGRldmlhdGlvbnMgZnJvbSB0aGUgc3RyYWlnaHQgbGluZSBpbiB0aGUgcGxvdCBiZWNhdXNlIG9mIHJhbmRvbSBiaW9sb2dpY2FsIHZhcmlhYmlsaXR5LCB3aGljaCBpcyBub3QgaW5kaWNhdGl2ZSBmb3IgZGV2aWF0aW9ucyBmcm9tIE5vcm1hbGl0eS4KCi0gU28gaXQgaXMgaW1wb3J0YW50IHRvIHRyYWluIHlvdXJzZWxmIHRvIGxlYXJuIHRvIGRpc3Rpbmd1aXNoIHN5c3RlbWF0aWMgZnJvbSByYW5kb20gZGV2aWF0aW9ucy4gCgojIyMgTm9ybWFsIGRhdGEKLSBXZSB3aWxsIGZpcnN0IHNpbXVsYXRlIGRhdGEgZnJvbSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiB0byBzaG93IGhvdyB0aGUgcGxvdHMgbG9vayBsaWtlIGZvciBkYXRhIHRoYXQgaXMgbWVldGluZyB0aGUgYXNzdW1wdGlvbnMuCgotIFdlIHdpbGwgc2ltdWxhdGUgZGF0YSBmcm9tIDkgc2FtcGxlcyB3aXRoIGEgbWVhbiBvZiAxOCBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIDkKCmBgYHtyfQpuIDwtIDIwCm11IDwtIDE4CnNpZ21hIDwtIDkKblNhbXAgPC05Cgpub3JtU2ltIDwtIG1hdHJpeChybm9ybShuKm5TYW1wLG1lYW49bXUsc2Q9c2lnbWEpLG5yb3c9bikgJT4lIGFzLmRhdGEuZnJhbWUKCm5vcm1TaW0gJT4lIGdhdGhlcihzYW1wLGRhdGEpICU+JSAKZ2dwbG90KGFlcyh4PWRhdGEpKSArCmdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uLCBmaWxsPS4uY291bnQuLiksYmlucz0zMCkgKwpnZW9tX2RlbnNpdHkoYWVzKHk9Li5kZW5zaXR5Li4pKSArCiAgZmFjZXRfd3JhcCh+c2FtcCkKCm5vcm1TaW0gJT4lIGdhdGhlcihzYW1wLGRhdGEpICU+JSAKICBnZ3Bsb3QoYWVzKHNhbXBsZT1kYXRhKSkgKwogIGdlb21fcXEoKSArCiAgZ2VvbV9xcV9saW5lKCkgKwpmYWNldF93cmFwKH5zYW1wKQpgYGAKClNvIGV2ZW4gZm9yIG5vcm1hbCBkYXRhIHdlIG9ic2VydmUgc29tZSBkZXZpYXRpb25zIQoKIyMjIFJlYWwgZGF0YQoKYGBge3J9Ck5IQU5FUyAlPiUgZmlsdGVyKEdlbmRlcj09ImZlbWFsZSImIWlzLm5hKEJNSSkpICU+JQogIGdncGxvdChhZXMoeD1CTUkpKSsKICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4sIGZpbGw9Li5jb3VudC4uKSkgKwogICB4bGFiKCJCTUkiKSArCiAgIGdndGl0bGUoIkFsbCBmZW1hbGVzIGluIHN0dWR5IikgKwogIGdlb21fZGVuc2l0eShhZXMoeT0uLmRlbnNpdHkuLikpCgpOSEFORVMgJT4lIGZpbHRlcihHZW5kZXI9PSJmZW1hbGUiJiFpcy5uYShCTUkpKSAlPiUKICBnZ3Bsb3QoYWVzKHNhbXBsZT1CTUkpKSArCiAgZ2VvbV9xcSgpICsKICBnZW9tX3FxX2xpbmUoKQpgYGAKClRoZSBRUS1wbG90IHNob3dzIHRoYXQgdGhlIHF1YW50aWxlcyBvZiB0aGUgZGF0YQogIC0gYXJlIGxhcmdlciAoYWJvdmUgdGhlIGxpbmUpIHRoYW4gdGhlc2UgZnJvbSB0aGUgTm9ybWFsIGluIHRoZSBsZWZ0IHRhaWw6IGNvbXByZXNzaW9uIG9mIHRoZSBsb3dlciB0YWlsCiAgLSBhcmUgbGFyZ2VyIChhYm92ZSB0aGUgbGluZSkgdGhhbiB0aGVzZSBmcm9tIHRoZSBOb3JtYWwgaW4gdGhlIHJpZ2h0IHRhaWw6IGxvbmcgdGFpbCB0byB0aGUgcmlnaHQKICAtIFdlIGNhbiBjbGVhcmx5IHNlZSB0aGF0IHRoZSBkYXRhIGFyZSBza2V3ZWQKICAKICAKCgoKCgo=